{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Predicting Flight Delays with sklearn\n",
    "\n",
    "In this notebook, we will be using features we've prepared in PySpark to predict flight delays via regression and classification."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Imports loaded...\n"
     ]
    }
   ],
   "source": [
    "import sys, os, re\n",
    "sys.path.append(\"lib\")\n",
    "import utils\n",
    "\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import iso8601\n",
    "import datetime\n",
    "print(\"Imports loaded...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load and Inspect our JSON Training Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original JSON file size: 4,676,447 Bytes\n",
      "Training items: 457,013\n",
      "Data loaded...\n"
     ]
    }
   ],
   "source": [
    "# Load and check the size of our training data. May take a minute.\n",
    "print(\"Original JSON file size: {:,} Bytes\".format(os.path.getsize(\"../data/simple_flight_delay_features.jsonl.bz2\")))\n",
    "\n",
    "training_data = utils.read_json_lines_file('../data/simple_flight_delay_features.jsonl.bz2')\n",
    "\n",
    "print(\"Training items: {:,}\".format(len(training_data))) # \n",
    "print(\"Data loaded...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Size of training data in RAM: 4,113,224 Bytes\n",
      "{'ArrDelay': 13.0, 'CRSArrTime': '2015-01-01T18:10:00.000Z', 'CRSDepTime': '2015-01-01T15:30:00.000Z', 'Carrier': 'AA', 'DayOfMonth': 1, 'DayOfWeek': 4, 'DayOfYear': 1, 'DepDelay': 14.0, 'Dest': 'DFW', 'Distance': 569.0, 'FlightDate': '2015-01-01T00:00:00.000Z', 'FlightNum': '1024', 'Origin': 'ABQ'}\n"
     ]
    }
   ],
   "source": [
    "# Inspect a record before we alter them\n",
    "print(\"Size of training data in RAM: {:,} Bytes\".format(sys.getsizeof(training_data))) # 50MB\n",
    "print(training_data[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Vectorize the Results (y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Results vectorized size: 3,656,200\n",
      "Results vectorized...\n"
     ]
    }
   ],
   "source": [
    "# Separate our results from the rest of the data, vectorize and size up\n",
    "results = [record['ArrDelay'] for record in training_data]\n",
    "results_vector = np.array(results)\n",
    "print(\"Results vectorized size: {:,}\".format(sys.getsizeof(results_vector))) # 45,712,160 bytes\n",
    "print(\"Results vectorized...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prepare Training Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ArrDelay and FlightDate removed from training data...\n"
     ]
    }
   ],
   "source": [
    "# Remove the two delay fields and the flight date from our training data\n",
    "for item in training_data:\n",
    "  item.pop('ArrDelay', None)\n",
    "  item.pop('FlightDate', None)\n",
    "print(\"ArrDelay and FlightDate removed from training data...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CRSArr/DepTime converted to unix time...\n"
     ]
    }
   ],
   "source": [
    "# Must convert datetime strings to unix times\n",
    "for item in training_data:\n",
    "  if isinstance(item['CRSArrTime'], str):\n",
    "    dt = iso8601.parse_date(item['CRSArrTime'])\n",
    "    unix_time = int(dt.timestamp())\n",
    "    item['CRSArrTime'] = unix_time\n",
    "  if isinstance(item['CRSDepTime'], str):\n",
    "    dt = iso8601.parse_date(item['CRSDepTime'])\n",
    "    unix_time = int(dt.timestamp())\n",
    "    item['CRSDepTime'] = unix_time\n",
    "print(\"CRSArr/DepTime converted to unix time...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Vectorize Training Data with `DictVectorizer`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sampled dimensions: [457,013]\n",
      "Size of DictVectorized vectors: 40,217,144 Bytes\n",
      "Training data vectorized...\n"
     ]
    }
   ],
   "source": [
    "# Use DictVectorizer to convert feature dicts to vectors\n",
    "from sklearn.feature_extraction import DictVectorizer\n",
    "\n",
    "print(\"Sampled dimensions: [{:,}]\".format(len(training_data)))\n",
    "vectorizer = DictVectorizer()\n",
    "training_vectors = vectorizer.fit_transform(training_data)\n",
    "print(\"Size of DictVectorized vectors: {:,} Bytes\".format(training_vectors.data.nbytes))\n",
    "print(\"Training data vectorized...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prepare Experiment by Splitting Data into Train/Test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(411311, 6979) (45702, 6979)\n",
      "(411311,) (45702,)\n",
      "Test train split performed...\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "  training_vectors,\n",
    "  results_vector,\n",
    "  test_size=0.1,\n",
    "  random_state=43\n",
    ")\n",
    "print(X_train.shape, X_test.shape)\n",
    "print(y_train.shape, y_test.shape)\n",
    "print(\"Test train split performed...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train our Model(s) on our Training Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Regressor library and metrics imported...\n"
     ]
    }
   ],
   "source": [
    "# Train a regressor\n",
    "from sklearn.linear_model import LinearRegression\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.metrics import median_absolute_error, r2_score\n",
    "print(\"Regressor library and metrics imported...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Regressor instantiated...\n"
     ]
    }
   ],
   "source": [
    "regressor = LinearRegression()\n",
    "print(\"Regressor instantiated...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.ensemble import GradientBoostingRegressor\n",
    "\n",
    "# regressor = GradientBoostingRegressor()\n",
    "# print(\"Swapped gradient boosting trees for linear regression!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Regressor fitted...\n"
     ]
    }
   ],
   "source": [
    "regressor.fit(X_train, y_train)\n",
    "print(\"Regressor fitted...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Predict Using the Test Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predictions made for X_test...\n"
     ]
    }
   ],
   "source": [
    "predicted = regressor.predict(X_test)\n",
    "print(\"Predictions made for X_test...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Evaluate and Visualize Model Accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Median absolute error:    6.95\n",
      "r2 score:                 0.881\n"
     ]
    }
   ],
   "source": [
    "from sklearn.metrics import median_absolute_error, r2_score\n",
    "\n",
    "# Median absolute error is the median of all absolute differences between the target and the prediction.\n",
    "# Less is better, more indicates a high error between target and prediction.\n",
    "medae = median_absolute_error(y_test, predicted)\n",
    "print(\"Median absolute error:    {:.3g}\".format(medae))\n",
    "\n",
    "# R2 score is the coefficient of determination. Ranges from 1-0, 1.0 is best, 0.0 is worst.\n",
    "# Measures how well future samples are likely to be predicted.\n",
    "r2 = r2_score(y_test, predicted)\n",
    "print(\"r2 score:                 {:.3g}\".format(r2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "# Plot outputs\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Cleans up the appearance\n",
    "plt.rcdefaults()\n",
    "\n",
    "plt.scatter(\n",
    "  y_test,\n",
    "  predicted,\n",
    "  color='blue',\n",
    "  linewidth=1\n",
    ")\n",
    "plt.grid(True)\n",
    "\n",
    "plt.xticks()\n",
    "plt.yticks()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
